package org.example;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import org.example.http.NRequest;
import org.example.http.NResponse;
import org.example.http.NServlet;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

// Netty
public class NTomcat {
    // 打开 Tomcat 源码，全局搜索ServerSocket
    private static final int PORT = 8080;
    private static Map<String, NServlet> serviceMap = new HashMap<>();
    private static String WEB_URL = "web.properties";

    private void init() {
        try {

            FileInputStream fileInputStream = new FileInputStream(this.getClass().getResource("/").getPath() + WEB_URL);
            Properties properties = new Properties();
            properties.load(fileInputStream);
            for (Object k : properties.keySet()) {
                String key = k.toString();
                if (key.endsWith(".url")) {
                    String keyPrefix = key.replaceAll("\\.url$", "");
                    String url = properties.getProperty(key);
                    String className = properties.getProperty(keyPrefix + ".className");
                    NServlet servlet = (NServlet) Class.forName(className).newInstance();
                    serviceMap.put(url, servlet);
                }
            }
        } catch (IOException | IllegalAccessException | InstantiationException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public void start() {
        init();
        // Netty 封装了NIO，Reactor模型，Boss，worker线程

        EventLoopGroup bossGroup = new NioEventLoopGroup();

        EventLoopGroup workerGroup = new NioEventLoopGroup();

        // netty 服务    ==>> nio中是ServerSocketChannel
        ServerBootstrap server = new ServerBootstrap();
        // 链路式编程
        server.group(bossGroup, workerGroup)
                // 主线程处理类,以后看到这种写法，底层就是用的反射
                .channel(NioServerSocketChannel.class)
                // 主线程的配置 分配线程最大数量 128
                .option(ChannelOption.SO_BACKLOG, 128)

                // 子线程处理类，handler
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    // 客户端初始化处理
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        // 无锁化串行编程，
                        // Netty 对 HTTP 协议的封装，顺序有要求的
                        // HttpResponseEncoder 编码器
                        ch.pipeline().addLast(new HttpResponseEncoder());
                        // HttpRequestDecoder 解码器
                        ch.pipeline().addLast(new HttpRequestDecoder());
                        // 业务处理逻辑
                        ch.pipeline().addLast(new NTomcatHandler());
                    }
                })
                // 针对子线程的配置 保持长连接
                .childOption(ChannelOption.SO_KEEPALIVE, true);

        // 启动服务器
        try {
            ChannelFuture f = server.bind(this.PORT).sync();
            System.out.println("N Tomcat 已启动，监听端口是：" + this.PORT);

            f.channel().closeFuture().sync();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

    }

    public static class NTomcatHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            if (msg instanceof HttpRequest) {
                HttpRequest req = (HttpRequest) msg;

                // 转交给我们自己的request 实现
                NRequest request = new NRequest(ctx, req);
                NResponse response = new NResponse(ctx, req);

                // 实际的业务处理
                if (serviceMap.containsKey(request.getUrl())) {
                    serviceMap.get(request.getUrl()).service(request, response);
                } else {
                    response.write("404 - Not Found");
                }
            }
        }
    }

    public static void main(String[] args) {
        new NTomcat().start();
    }
}
